package cn.kais.drawer.bean;

import cn.kais.drawer.AxisUtil;
import cn.kais.drawer.UnitUtil;
import cn.kais.drawer.coms.BaseComs;
import cn.kais.drawer.coms.TextCom;
import cn.kais.drawer.menu.MenuBean;
import cn.kais.drawer.menu.MenuNumberRound;
import cn.kais.drawer.unit.UnitNumber;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;

import java.awt.*;
import java.awt.font.TextAttribute;
import java.text.AttributedString;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class BeanNumber extends BeanBasic {

    public String number = "2999999.3"; // 数值
    public String positiveFlag;  // 正数前置符号
    public String negativeFlag;  // 负数前置符号

    public int top;
    public int left;
    public int width;
    public int height;

    public String textAlign;  // 水平对齐方式  左 中 右
    public String verticalAlign; // 垂直对齐方式 上 中 下

    public Color color; // 文本颜色
    public Color bColor; // 背景颜色

    public String scale = "2"; // 小数位
    public String round = "2"; // 舍入方式
    public String mark = ""; // 千分符

    public String calcType = ""; // 计算类型 +加-减*乘/除%余
    public String calcNumber = ""; // 计算数值

    public String exceedingDisplay = "1"; // 超出显示效果 1 超出隐藏 2自动缩放

    public JSONObject integerTextStyle; // 整数样式
    public JSONObject decimalTextStyle; // 小数样式

    public JSONObject decimalPointTextStyle; // 小数点样式
    public String decimalPoint = ""; // 小数点替换
    public int fontSpecial = 1; // 小数点浮动方式

    public String preText = "¥"; // 前缀
    public String sufText = "元"; // 后缀
    public JSONObject preTextStyle; // 前缀样式
    public JSONObject sufTextStyle; // 后缀样式

    public Graphics2D sd; // 绘制

    public BeanNumber(Graphics2D sd, JSONObject com) {
//        System.out.println(com.toJSONString());
        menu = MenuBean.NUMBER;
        this.sd = sd;
        this.top = com.getInteger("top");
        this.left = com.getInteger("left");
        this.width = com.getInteger("width");
        this.height = com.getInteger("height");

        // flex-start center flex-end
        this.textAlign = com.getString("textAlign");
        this.verticalAlign = com.getString("verticalAlign");

        this.number = com.getString("text");
        this.positiveFlag = com.getString("positiveFlag");
        this.negativeFlag = com.getString("negativeFlag");

        this.scale = com.getString("decimalplaces");
        this.round = com.getString("roundingMode");
        this.mark = com.getString("thousandSeparator");

        // 超出显示效果
        this.exceedingDisplay = com.getString("exceedingDisplay");
        this.calcType = com.getString("calcType");
        this.calcNumber = com.getString("calcNumber");

        this.integerTextStyle = com.getJSONObject("integerTextStyle");
        // 小数 只有顶部对齐和底部对齐  使用 另外字段覆盖其内部对齐字段
        this.decimalTextStyle = com.getJSONObject("decimalTextStyle");
        this.fontSpecial = com.getIntValue("fontSpecial");
        if (this.fontSpecial == 1) {
            this.decimalTextStyle.put("alignType", 1);
        } else {
            this.decimalTextStyle.put("alignType", 3);
        }

        this.decimalPoint = com.getString("decimalPoint");
        // 小数点默认底部对齐,并且始终底部对齐
        this.decimalPointTextStyle = com.getJSONObject("decimalPointTextStyle");
        this.decimalPointTextStyle.put("alignType", 3);

        this.preText = com.getString("preText");
        this.sufText = com.getString("sufText");
        this.preTextStyle = com.getJSONObject("preTextStyle");
        this.sufTextStyle = com.getJSONObject("sufTextStyle");

        this.color = UnitUtil.toColor(com.getString("fontColor"));
        this.bColor = UnitUtil.toColor(com.getString("bgColor"));

        this.create();
    }

    /**
     * 对齐方式
     * 后缀对齐方式: alignType：1顶部对齐 2垂直居中 3底部对齐 4小数上方对齐 5小数下方对齐
     * 前缀对齐方式：alignType：1顶部对齐 2垂直居中 3底部对齐
     * 小数对齐方式：alignType：1顶部对齐 2垂直居中 3底部对齐  // 废弃
     * 小数对齐方式：fontSpecial：1顶部对齐  2底部对齐    // 调整 为小数对齐方式
     * 小数点对齐方式：永远底部对齐
     * 0：前置 1：正数 2：小数点 3：小数 4：后置
     */
    private void create() {
        // 区域框 测试使用
        if (this.isShowBorder) {
            new BeanBorder(this.sd, this.top, this.left, this.width, this.height);
        }

        // 背景
        sd.setColor(this.bColor);
        sd.fillRect(this.left, this.top, this.width, this.height);

        // 格式化 转为目标字符串
        int scale = UnitUtil.doStr2Int(this.scale); // 小数位
        MenuNumberRound round = MenuNumberRound.onParseCode(this.round); // 舍入模式

        String number0 = UnitNumber.doCountNumber(this.number, this.calcType, this.calcNumber); // 先进行加减乘除计算
        System.out.println(number0);
        if (Objects.equals(number0, "不是数字")) {
            sd.setColor(Color.red);
            sd.fillRect(this.left, this.top, this.width, this.height);
            this.integerTextStyle.put("text", number0);
            this.integerTextStyle.put("fontSize", 24);
            TextCom com = onCreateText(this.integerTextStyle);
            assert com != null;
            this.sd.drawString(com.attr.getIterator(), this.left + (this.width - com.width) / 2, (this.height - com.height) / 2 + (this.top + com.height));
            return;
        }
        String number1 = UnitNumber.doFormatNumber(number0, round, scale, this.mark); // 增加千分符
        String number2 = UnitNumber.doFixNumber(number1, this.positiveFlag, this.negativeFlag); // 增加正负标志
        // 拆分
        List<String> numbers = UnitNumber.doSub5ForNumber(number2, this.preText, this.sufText); // 拆分成 5个 独立字符串
        List<JSONObject> items = new ArrayList<>();
        for (int i = 0; i < numbers.size(); i++) {
            String str = numbers.get(i);
            switch (i) {
                case 0: // 前缀
                    this.preTextStyle.put("text", str);
                    items.add(this.preTextStyle);
                    break;
                case 1: // 整数
                    this.integerTextStyle.put("text", str);
                    items.add(this.integerTextStyle);
                    break;
                case 2: // 小数点
                    if (StringUtils.isNotBlank(this.decimalPoint) && !this.decimalPoint.equals(str) && scale > 0) {
                        str = this.decimalPoint;
                    }
                    this.decimalPointTextStyle.put("text", str);
                    items.add(this.decimalPointTextStyle);
                    break;
                case 3: // 小数
                    this.decimalTextStyle.put("text", str);
                    items.add(this.decimalTextStyle);
                    break;
                case 4: // 后缀
                    this.sufTextStyle.put("text", str);
                    items.add(this.sufTextStyle);
                    break;
            }
        }

        JSONObject wh = new JSONObject();
        wh.put("maxWei", 0);
        wh.put("maxHei", 0);
        List<BaseComs> coms = new ArrayList<>();
        this.doCountWeiHeiAddComs(items, coms, wh);

        int maxWei = wh.getInteger("maxWei");
        int maxHei = wh.getInteger("maxHei");
        System.out.println("初始宽度：" + maxWei);
        System.out.println("初始高度：" + maxHei);
        // 超出缩放需要重重宽度
        if (maxWei > this.width && Objects.equals(this.exceedingDisplay, "2")) {
            int aw = maxWei - this.width;
            double ab = (double) aw / maxWei;
            for (JSONObject item : items) {
                int size = item.getIntValue("fontSize");
                int ns = (int) (size - (size * ab));
                item.put("fontSize", ns);
            }
            this.doCountWeiHeiAddComs(items, coms, wh);
            maxWei = wh.getInteger("maxWei");
            maxHei = wh.getInteger("maxHei");
            System.out.println("重置宽度：" + maxWei);
            System.out.println("重置高度：" + maxHei);
        }

        System.out.println("应有宽度：" + this.width);
        System.out.println("应有高度：" + this.height);
        for (int i = 0; i < coms.size(); i++) {
            BaseComs base = coms.get(i);
            if (null != base) {
                TextCom text = (TextCom) base;
                int x = AxisUtil.doCountNumberItemX(i, coms);
                int xx = 0;
                switch (this.textAlign) {
                    case "flex-start": // 左对齐
                        // 1.正常绘制
                        break;
                    case "flex-end": // 右对齐
                        // 1.计算文本宽度 left = left + (width - fontwidth)
                        xx = this.width - maxWei;
                        break;
                    case "center": // 水平居中
                        // 1.计算文本宽度 left = left + ((width - fontwidth) / 2)
                        xx = (this.width - maxWei) / 2;
                        break;
                }

                int y = AxisUtil.doCountNumberItemY(i, maxHei, text.height, text.align);
                int yy = 0;
                switch (this.verticalAlign) {
                    case "flex-start": // 上对齐
                        // 1.正常绘制
                        break;
                    case "flex-end": // 下对齐
                        // 1.计算文本高度 top = (top + fontsize) + (height - fontsize)
                        yy = this.height - maxHei;
                        break;
                    case "center": // 垂直居中
                        // 1.计算文本高度 top = (top + fontsize) + ((height - fontsize) / 2)
                        yy = (this.height - maxHei) / 2;
                        break;
                }
                // 绘制
                this.sd.drawString(text.attr.getIterator(), x + xx + this.left, y + yy + this.top + text.height);
            }
        }
    }

    /**
     * Json 列表转换 组件列表 并计算出最大宽度 高度
     *
     * @param items Json 列表
     * @param coms  组件 列表
     * @param wh    最大宽度 最大高度
     */
    private void doCountWeiHeiAddComs(List<JSONObject> items, List<BaseComs> coms, JSONObject wh) {
        int maxWei = 0;
        int maxHei = 0;
        coms.clear();
        for (JSONObject item : items) {
            TextCom com = onCreateText(item);
            coms.add(com);
            if (null == com) continue;
            if (com.height > maxHei) maxHei = com.height;
            if (com.align == 4 || com.align == 5) {
                BaseComs base3 = coms.get(3);  // 如果当前宽度 大于 上一个的宽度，则已当前宽度为准
                if (base3 != null && (com.width > base3.width)) {
                    maxWei = maxWei - base3.width + com.width;
                } else {
                    maxWei = maxWei + com.width;
                }
            } else {
                maxWei = maxWei + com.width;
            }
        }
        wh.put("maxWei", maxWei);
        wh.put("maxHei", maxHei);
    }

    /**
     * 每个组件Json创建独立的 text组件
     *
     * @param com 组件Json
     */
    private TextCom onCreateText(JSONObject com) {
        System.out.println(com.toJSONString());
        String text = com.getString("text");
        if (text.equals("-")) return null;

        String fontName = com.getString("font");
        int fontSize = com.getIntValue("fontSize");
        // 样式：加粗 斜体 下划线
        boolean isBold = com.getBoolean("isBold");  // 是否加粗
        boolean isItalic = com.getBoolean("isItaly"); // 是否斜体
        String isUnderline = com.getString("isUnderline"); // 是否下划线
        String isCenterline = com.getString("isCenterline"); // 是否中横线

        // 字体
        Font font = UnitUtil.toFont(fontName, fontSize, isBold, isItalic);
        FontMetrics metrics = this.sd.getFontMetrics(font);
        int fontHeight = metrics.getAscent() - metrics.getDescent() - metrics.getLeading();
        int fontWidth = metrics.stringWidth(text);

        // 绘制配置
        AttributedString as = new AttributedString(text);
        as.addAttribute(TextAttribute.FONT, font); // 文本字体
        as.addAttribute(TextAttribute.FOREGROUND, this.color); // 文本颜色
        if (null != isUnderline && !isUnderline.equals("none")) { // 下划线
            as.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
        }
        if (null != isCenterline && !isCenterline.equals("none")) { // 中横线
            as.addAttribute(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
        }

        // 对齐方式
        int align = com.getIntValue("alignType");
        return new TextCom(as, fontWidth, fontHeight, align);
    }

}
